package com.lineage.echo;

import com.lineage.commons.system.LanSecurityManager;
import com.lineage.config.Config;
import com.lineage.config.ConfigIpCheck;
import com.lineage.echo.encryptions.Encryption;
import com.lineage.list.OnlineUser;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.serverpackets.S_Disconnect;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.L1Account;
import com.lineage.server.thread.GeneralThreadPool;
import com.lineage.server.utils.StreamUtil;
import com.lineage.server.utils.SystemUtil;
import java.io.IOException;
import java.math.BigInteger;
import java.net.Socket;
import java.net.SocketException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ClientExecutor extends OpcodesClient implements Runnable {
  private static final Log _log = LogFactory.getLog(ClientExecutor.class);
  
  private static final int M = 3;
  
  private static final int O = 2;
  
  public int _xorByte;
  
  public long _authdata;
  
  private Socket _csocket;
  
  private L1Account _account;
  
  private L1PcInstance _activeChar;
  
  private StringBuilder _ip;
  
  private StringBuilder _mac;
  
  private int _kick;
  
  private boolean _isStrat;
  
  private EncryptExecutor _encrypt;
  
  private DecryptExecutor _decrypt;
  
  private PacketHandlerExecutor _handler;
  
  private Encryption _keys;
  
  private int _error;
  
  private int _saveInventory;
  
  private int _savePc;
  
  private PacketHc o;
  
  private PacketHc m;
  
  private byte _loginStatus;
  
  public ClientExecutor(Socket socket) throws IOException {
    this._csocket = null;
    this._account = null;
    this._activeChar = null;
    this._ip = null;
    this._mac = null;
    this._kick = 0;
    this._isStrat = true;
    this._error = -1;
    this._saveInventory = 0;
    this._savePc = 0;
    this._xorByte = -16;
    this._loginStatus = 2;
    this._csocket = socket;
    if (Config.LOGINS_TO_AUTOENTICATION) {
      int randomNumber = (int)(Math.random() * 9.0E8D) + 255;
      this._xorByte = randomNumber % 255 + 1;
      this._authdata = (new BigInteger(Integer.toString(randomNumber))).modPow(new BigInteger(Config.RSA_KEY_E), new BigInteger(Config.RSA_KEY_N)).longValue();
    } 
    this._ip = (new StringBuilder()).append(socket.getInetAddress().getHostAddress());
    this._handler = new PacketHandler(this);
    this._keys = new Encryption();
    this._decrypt = new DecryptExecutor(this, socket.getInputStream());
    this._encrypt = new EncryptExecutor(this, socket.getOutputStream());
  }
  
  public void start() {}
  
  public void run() {
    this.o = new PacketHc(this, 2);
    GeneralThreadPool.get().schedule(this.o, 0L);
    try {
      this._encrypt.satrt();
      this._encrypt.outStart();
      boolean isEcho = false;
      while (this._isStrat) {
        byte[] decrypt = null;
        try {
          decrypt = readPacket();
        } catch (Exception e) {
          break;
        } 
        if (decrypt.length > 1440) {
          _log.warn("客户端送出长度异常封包:" + this._ip.toString() + " 帐号:" + (
              (this._account != null) ? this._account.get_login() : "未登入"));
          LanSecurityManager.BANIPMAP.put(this._ip.toString(), Integer.valueOf(100));
          break;
        } 
        if (this._account != null) {
          if (!OnlineUser.get().isLan(this._account.get_login()))
            break; 
          if (!this._account.is_isLoad())
            break; 
        } 
        int opcode = decrypt[0] & 0xFF;
        if (this._activeChar == null) {
          if (opcode == 14) {
            if (ConfigIpCheck.IPCHECKPACK) {
              this._csocket.setSoTimeout(0);
              LanSecurityManager.BANIPPACK.remove(this._ip.toString());
            } 
            isEcho = true;
          } else if (opcode == 119) {
            this.m = new PacketHc(this, 3);
            GeneralThreadPool.get().schedule(this.m, 0L);
            set_savePc(Config.AUTOSAVE_INTERVAL);
            set_saveInventory(Config.AUTOSAVE_INTERVAL_INVENTORY);
          } 
          if (!isEcho)
            continue; 
          this._handler.handlePacket(decrypt);
          continue;
        } 
        if (!isEcho)
          continue; 
        if (this.m == null)
          continue; 
        switch (opcode) {
          case 122:
            this._isStrat = false;
            continue;
          case 7:
          case 25:
          case 138:
            this._handler.handlePacket(decrypt);
            continue;
          case 29:
            this.m.requestWork(decrypt);
            continue;
        } 
        this.o.requestWork(decrypt);
      } 
    } catch (Exception exception) {
    
    } finally {
      set_savePc(-1);
      set_saveInventory(-1);
      close();
    } 
  }
  
  public void close() {
    try {
      String mac = null;
      if (this._mac != null)
        mac = this._mac.toString(); 
      if (this._csocket == null)
        return; 
      this._kick = 0;
      if (this._account != null)
        OnlineUser.get().remove(this._account.get_login()); 
      if (this._activeChar != null)
        quitGame(); 
      String ipAddr = this._ip.toString();
      String account = null;
      if (this._kick < 1 && this._account != null)
        account = this._account.get_login(); 
      this._decrypt.stop();
      this._encrypt.stop();
      StreamUtil.close(this._csocket);
      this._handler = null;
      this._mac = null;
      this._ip = null;
      this._activeChar = null;
      this._account = null;
      this._decrypt = null;
      this._encrypt = null;
      this._csocket = null;
      this._keys = null;
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.append("\n--------------------------------------------------");
      stringBuilder.append("\n       客户端 离线: (");
      if (account != null)
        stringBuilder.append(String.valueOf(String.valueOf(account)) + " "); 
      if (mac != null)
        stringBuilder.append(" " + mac + " / "); 
      stringBuilder.append(String.valueOf(String.valueOf(ipAddr)) + ") 完成连线中断!!");
      stringBuilder.append("\n--------------------------------------------------");
      _log.info(stringBuilder.toString());
      SystemUtil.printMemoryUsage(_log);
    } catch (Exception exception) {}
  }
  
  public L1Account getAccount() {
    return this._account;
  }
  
  public void setAccount(L1Account account) {
    this._account = account;
  }
  
  public String getAccountName() {
    if (this._account == null)
      return null; 
    return this._account.get_login();
  }
  
  public L1PcInstance getActiveChar() {
    return this._activeChar;
  }
  
  public void setActiveChar(L1PcInstance pc) {
    this._activeChar = pc;
  }
  
  public StringBuilder getIp() {
    return this._ip;
  }
  
  public StringBuilder getMac() {
    return this._mac;
  }
  
  public boolean setMac(StringBuilder mac) {
    this._mac = mac;
    return true;
  }
  
  public Socket get_socket() {
    return this._csocket;
  }
  
  public boolean kick() {
    try {
      this._encrypt.encrypt((ServerBasePacket)new S_Disconnect());
    } catch (Exception exception) {}
    quitGame();
    this._kick = 1;
    this._isStrat = false;
    close();
    return true;
  }
  
  public void quitGame() {
    try {
      if (this._activeChar == null)
        return; 
      synchronized (this._activeChar) {
        QuitGame.quitGame(this._activeChar);
        this._activeChar = null;
      } 
    } catch (Exception exception) {}
  }
  
  private byte[] readPacket() {
    try {
      byte[] data = null;
      data = this._decrypt.decrypt();
      return data;
    } catch (Exception ex) {
      return null;
    } 
  }
  
  public EncryptExecutor out() {
    return this._encrypt;
  }
  
  public Encryption get_keys() {
    return this._keys;
  }
  
  public void set_keys(Encryption keys) {
    this._keys = keys;
  }
  
  public int get_error() {
    return this._error;
  }
  
  public void set_error(int error) {
    this._error = error;
    if (this._error >= 2)
      kick(); 
  }
  
  public int get_saveInventory() {
    return this._saveInventory;
  }
  
  public void set_saveInventory(int saveInventory) {
    this._saveInventory = saveInventory;
  }
  
  public int get_savePc() {
    return this._savePc;
  }
  
  public void set_savePc(int savePc) {
    this._savePc = savePc;
  }
  
  public byte getLoginStatus() {
    return this._loginStatus;
  }
  
  public void setLoginStatus(byte i) {
    this._loginStatus = i;
  }
  
  public void RemoveSocket() {
    try {
      this._csocket.setSoTimeout(0);
    } catch (SocketException e) {
      e.printStackTrace();
    } 
  }
  
  public void SetSocket(int time) {
    try {
      this._csocket.setSoTimeout(time * 1000);
    } catch (SocketException e) {
      e.printStackTrace();
    } 
  }
}
